Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

DataHub : le tracking serveur opéré par Qwant

← Sommaire | ← Chapitre 54

Document technique original

Cette page est une synthèse. L'analyse complète, avec la chronologie Git, les catégories d'événements, les fichiers et les commits contrôlés, est disponible ici : Le DataHub de Qwant — journalisation serveur, recherches, clics et publicités.

Avertissement probatoire

Ce chapitre décrit les capacités du code versionné dans le dépôt API-API-TAG-PACKAGER, en particulier dans le tag v1.32.1 du 22 décembre 2016. Une capacité inscrite dans une version de release n'établit pas, à elle seule, son activation sur tout le trafic, la réception de chaque événement, sa durée de conservation ou son exploitation effective par les équipes de Qwant.

1. Réponse synthétique

Le code source établit qu'en 2016 Qwant avait développé un système interne centralisé désigné comme DataHub. Ce système était capable de recevoir des événements concernant :

  • les requêtes de recherche ;
  • les clics sur les résultats ;
  • les impressions publicitaires ;
  • les appels aux fournisseurs externes ;
  • certaines actions de compte et de boards ;
  • les erreurs applicatives ;
  • des signaux de lutte contre le scraping et les abus.

Chaque événement pouvait être associé à une enveloppe comprenant notamment :

  • l'adresse IP complète vue par l'API ;
  • le User-Agent ;
  • la locale ;
  • l'URI HTTP complète ;
  • le référent ;
  • la date ;
  • l'environnement et la version applicative ;
  • à partir d'août 2016, un hash stable dérivé de l'adresse IP.

Cette association répétée entre une action, son contenu, un instant et des identifiants techniques étaye la qualification de tracking serveur individualisable côté Qwant.

Elle ne démontre pas, sans éléments supplémentaires :

  • l'identification civile de chaque utilisateur ;
  • la constitution effective d'un profil publicitaire longitudinal ;
  • une transmission du contenu du DataHub à Microsoft ;
  • la durée de conservation des événements ;
  • l'utilisation du système pour surveiller une personne déterminée ;
  • une faute ou une intention pénale.

2. Qui a mis en place le DataHub ?

L'historique Git attribue l'implémentation principale du nouveau logger à Thomas Decaux.

Le commit structurant est :

48a167106a2bf14b7521767d92242bf41bda6966
31 mars 2016
t.decaux@qwant.com
#QAPI-370 Integrate dataHub aka new logger

Ce commit ajoute ou transforme notamment :

  • www/application/config/logger.php ;
  • www/application/hooks/QwantHook.php ;
  • www/application/libraries/search_service.php ;
  • www/application/models/logger.php ;
  • le contrôleur chargé de certains clics.

Pierre Vignaux apparaît ensuite comme le principal intégrateur de la fonctionnalité dans prelive et master, ainsi que comme auteur ou correcteur de plusieurs mécanismes de recherche, de score antispam et de bannissement.

D'autres contributeurs interviennent sur des parties identifiables :

  • Nghia Duong sur les exceptions, les erreurs de connexion et feedSearchSuggest() ;
  • Jonathan Cassar sur certains merges et composants périphériques ;
  • Thomas Decaux à nouveau sur les impressions publicitaires, les clics, le hash client et de nombreuses extensions du schéma.

Parmi les étapes importantes :

Date Commit Fonction ajoutée ou modifiée
14 juin 2016 c3c69dff89 transport phpAmqpLib et plusieurs serveurs RabbitMQ
21 juillet 2016 86e9620bda impressions publicitaires
3 août 2016 7799a5c560 hash client stable et score antispam
31 août 2016 4bdfca906f détail des annonces publicitaires
7 septembre 2016 c5f1e1d72d actions de compte, boards, notes et contacts
9 septembre 2016 451981b7ea contrôleur de clics SERP et page d'accueil
5 décembre 2016 d6aa1cf0c6 bannissement distingué comme produit par le DataHub

Cette attribution est une attribution Git. Elle ne prouve pas qui a décidé les finalités du système, qui connaissait l'ensemble de son périmètre ou qui l'a autorisé au niveau de la direction.

3. Comment fonctionne le DataHub ?

Le chemin visible dans le code est le suivant :

Requête adressée à l'API Qwant
        ↓
Création d'un ou plusieurs événements
        ↓
Logger::logEvent()
        ↓
Tampon en mémoire pendant la requête
        ↓
QwantHook::onShutDown()
        ↓
Logger::flushEvents()
        ↓
Message JSON publié dans RabbitMQ
        ↓
Consommateurs DataHub absents du dépôt étudié

Le logger accumule les événements dans un tableau en mémoire. À la fin du traitement, un hook récupère le logger, ajoute éventuellement une erreur PHP fatale puis tente de vider le tampon.

Dans v1.32.1, le transport :

  • utilise AMQPStreamConnection ;
  • essaie plusieurs hôtes ;
  • se connecte sur le port 5672 ;
  • publie dans l'échange amq.direct ;
  • utilise la routing key v1 ;
  • encode chaque événement en JSON.

La configuration dite de production vise deux adresses IP privées. La configuration générale utilise un hostname interne contenant queue.analytics.qwant.plive.

Le dépôt ne contient pas le consommateur de la queue. Il ne permet donc pas de déterminer directement :

  • la base de données finale ;
  • les index ou tables créés ;
  • les durées de conservation ;
  • les tableaux de bord ;
  • les personnes habilitées ;
  • les traitements statistiques effectivement appliqués.

Le code ignore aussi les exceptions de connexion et ne montre pas d'accusé de réception du broker. Il prouve une tentative d'envoi, pas la réception certaine de chaque message.

4. L'enveloppe commune de chaque événement

Logger::logEvent() ajoute automatiquement plusieurs blocs aux données propres à l'événement.

Bloc Données principales
Événement date Unix, identifiant, nom et version du schéma
Produit module, version, environnement, type d'API et application
Client IP complète, origine réseau, locale, User-Agent et hash client
Requête HTTP méthode, host, URI, serveur, référent et score antispam
Données métier recherche, clic, publicité, erreur ou action concernée

Le système n'enregistre donc pas seulement un compteur anonyme. Il peut associer le contenu de l'action aux métadonnées techniques de la connexion.

IP complète et hash stable

Pour chaque événement, le champ client.ip reçoit l'adresse retournée par ip_address().

À partir du 3 août 2016, une IP publique reçoit également un hash calculé selon le principe :

SHA-256(IP + sel serveur)

À sel inchangé, une même IP produit le même hash dans des événements successifs. Ce mécanisme permet techniquement de rapprocher des événements associés à une même adresse au cours du temps.

Il ne constitue pas un identifiant certain de personne : une IP peut être partagée, dynamique, masquée par un VPN ou utilisée par plusieurs membres d'un foyer ou d'une entreprise.

Identifiant d'événement

L'identifiant propre à chaque événement contient également :

  • le mois, le jour et l'heure ;
  • le produit et le type d'événement ;
  • un fragment de MD5 fondé sur IP + User-Agent ;
  • une partie aléatoire.

5. Ce que le DataHub enregistre sur les recherches

Dans v1.32.1, l'événement search comporte notamment :

  • la requête complète ;
  • la locale ;
  • le domaine de recherche ;
  • l'offset et le nombre de résultats demandés ;
  • le nombre de résultats obtenus ;
  • le statut du cache ;
  • l'onglet ;
  • la durée ;
  • les filtres ;
  • le score antispam ;
  • le statut HTTP.

search_service.php appelle le logger aussi bien :

  • après une recherche exécutée par un fournisseur ou modèle ;
  • lorsque le résultat est resservi depuis le cache ;
  • pour certains motifs bloqués comme abusifs.

Le cache ne supprime donc pas le tracking de la requête : il change la valeur du champ cached.

Toutes les tentatives ne sont pas nécessairement enregistrées sous forme d'événement search. Certaines validations peuvent retourner avant l'appel à logSearch(), et une exception peut produire seulement un événement d'erreur.

6. Les clics sur les résultats

Le contrôleur LoggerClickAPIController prévoit une route de type :

api/click/(:any)

Lorsqu'un clic valide lui est transmis, l'événement peut contenir :

  • la requête ;
  • l'URL cible complète ;
  • le host, le schéma et le domaine cible ;
  • la position du résultat ;
  • le domaine de recherche ;
  • le type de lien, notamment publicité ou résultat normal ;
  • la locale ;
  • l'appareil ;
  • l'onglet.

Le code prévoit aussi des événements pour :

  • les clics sur la page d'accueil ;
  • les clics Cinetick, avec film, cinéma, ville et séance.

Le dépôt API prouve ce que l'endpoint fait lorsqu'il est appelé. Il ne prouve pas que toutes les interfaces Qwant lui adressaient systématiquement chaque clic. Le code front ou des traces réseau seraient nécessaires pour mesurer cette couverture.

7. Les impressions publicitaires

Lorsque search_ads.php interroge Bing Ads, Qwant construit parallèlement un événement interne ads_print contenant :

  • le mot-clé recherché ;
  • l'appareil ;
  • la locale ;
  • l'onglet ;
  • le domaine ;
  • le nombre d'annonces ;
  • le titre et l'URL source de chaque annonce retournée.

L'enveloppe DataHub ajoute l'IP complète, le hash de l'IP, le User-Agent et le contexte HTTP.

La portée la plus solide est donc :

Qwant disposait d'un événement interne capable de rapprocher une requête publicitaire, les annonces affichées et des identifiants techniques côté serveur.

Le code ne suffit pas à démontrer que ces données ont été transformées en profil publicitaire individuel durable.

8. Ne pas confondre DataHub Qwant et flux Bing

Le parcours publicitaire comporte deux flux distincts.

Flux adressé à Bing Ads

Le code adresse à Bing Ads :

  • la requête ;
  • le User-Agent ;
  • le référent ;
  • un header X-Search-ClientIP.

Pour une IPv4, anonymizeIp() remplace le dernier octet par zéro :

82.65.234.124 → 82.65.234.0

La fonction ne traite que les adresses contenant un point. Une IPv6 pourrait donc être renvoyée inchangée dans ce chemin, sous réserve du format reçu en production.

Flux interne DataHub

Le DataHub Qwant reçoit, dans son enveloppe commune, l'IP complète vue par l'API. Il serait donc erroné d'écrire que le DataHub ne conservait que l'IPv4 tronquée au /24.

Inversement, aucun code contrôlé ne montre que le contenu du DataHub interne était envoyé à Microsoft. La transmission à Bing et la journalisation interne Qwant doivent être analysées séparément.

Pour l'articulation avec Microsoft et les politiques de confidentialité, voir également le chapitre 44 et le chapitre 53 sur l'IP /24.

search_suggest

La fonction feedSearchSuggest() enregistre séparément les recherches Web normalisées dans une table SQL search_suggest.

Elle calcule un hash journalier incorporant :

  • la date ;
  • l'IP ;
  • la locale ;
  • la requête.

La requête et la locale sont insérées dans la table. Le commentaire indique que ces données doivent servir à l'optimisation des suggestions.

Ce mécanisme n'utilise pas le transport RabbitMQ du DataHub. Le TTL d'une heure visible dans la fonction concerne le cache de déduplication, pas la durée de conservation SQL.

click_url_temp

Après un clic SERP, url_model->saveUrl() écrit aussi dans un index Elasticsearch nommé click_url_temp :

  • le hash journalier ;
  • l'URL ;
  • la requête ;
  • la locale ;
  • la position ;
  • la date.

Un clic reçu peut donc alimenter à la fois le DataHub et un document Elasticsearch distinct. Le mot temp ne suffit pas à établir une durée d'effacement.

10. Autres événements suivis

Le DataHub ne se limite pas à la recherche et à la publicité.

Produit Exemples d'événements
Compte inscription, suppression demandée ou exécutée, erreur de connexion, flood
Boards création de board, création de note, flood
Core contact et feedback
IA requête réussie et clic Cinetick
API erreur PHP, exception, erreur 404 et ancien logger
Fournisseurs externes URL appelée, host, code HTTP, durée et volume téléchargé

Certaines actions de compte ou de board contiennent un identifiant numérique d'utilisateur. L'événement standard de recherche ne contient pas directement cet identifiant. Le dépôt ne montre pas une jointure systématique entre les recherches et un compte nommé.

11. Une fonction opérationnelle d'antiflood

Le DataHub n'est pas seulement présenté comme un outil d'analytics.

Dans user_model.php, isBannedByDataHub() consulte dans Couchbase une clé calculée à partir du même hash salé de l'IP. Le commentaire indique :

Checks in couchbase generated by DataHub if an IP is banned

Dans MY_Controller.php, l'existence de cette clé peut provoquer une réponse :

429 Too Many Requests

Le code distingue ce bannissement de ceux fondés sur une blacklist IP classique ou sur IP + User-Agent.

Cette boucle est donc visible :

Événements et hash client
        ↓
Traitement DataHub absent du dépôt
        ↓
Clé de blacklist Couchbase
        ↓
Refus d'accès par l'API

Le dépôt ne contient pas l'algorithme qui décide de créer la clé. Les critères, seuils et durées du bannissement restent inconnus.

Le logger étudié :

  • ne dépose pas lui-même de cookie ;
  • ne charge pas de pixel ;
  • n'exécute pas de script de fingerprinting dans le navigateur ;
  • utilise les données de la requête HTTP et les paramètres transmis à l'API.

L'absence de cookie ne signifie donc pas l'absence de tracking. Il faut distinguer :

  • le traceur client, déposé ou exécuté dans le navigateur ;
  • le tracking serveur, qui associe des actions successives à des identifiants techniques reçus par le serveur.

Dans les producteurs contrôlés, aucune condition liée à DNT, au consentement ou à une opposition utilisateur n'est visible avant l'enregistrement. La seule exclusion concerne les User-Agents techniques qwant-monitor et qwant-stresstest, sauf pour les erreurs.

13. Ce que le code prouve

Le dépôt permet d'affirmer que :

  1. le terme DataHub est explicitement employé ;
  2. une architecture d'envoi JSON vers une queue analytics interne est implémentée ;
  3. les événements peuvent contenir l'IP complète, le User-Agent, l'URI et le référent ;
  4. un hash stable de l'IP est ajouté à partir d'août 2016 ;
  5. les recherches ordinaires et celles servies depuis le cache peuvent être journalisées ;
  6. les clics et les impressions publicitaires disposent d'événements dédiés ;
  7. les annonces affichées peuvent être enregistrées avec la requête correspondante ;
  8. des actions de compte et de contenu alimentent aussi le système ;
  9. une blacklist générée en aval par le DataHub peut conduire à refuser l'accès à l'API ;
  10. des tags de release et une configuration nommée production contiennent ce mécanisme.

14. Ce qui reste à démontrer

Le code seul ne permet pas d'établir :

  • le déploiement de chaque version sur tout le trafic ;
  • la réception de chaque message ;
  • le schéma du stockage aval ;
  • les durées de conservation ;
  • les habilitations d'accès ;
  • les traitements statistiques réellement effectués ;
  • la constitution d'un profil publicitaire longitudinal par personne ;
  • la correspondance entre un hash et une identité civile ;
  • la transmission du DataHub à Microsoft ;
  • le suivi d'une personne déterminée ;
  • une faute juridique ou une intention de dissimulation.

15. Conclusion probatoire

La formulation la plus étayée est la suivante :

Dès 2016, Qwant avait développé et versionné un dispositif interne de journalisation serveur désigné comme DataHub. Dans le tag v1.32.1, ce dispositif était capable d'enregistrer les requêtes de recherche, les clics et les impressions publicitaires avec l'adresse IP complète, le User-Agent, le contexte HTTP et un hash stable dérivé de l'IP. Il permettait ainsi un tracking serveur individualisable côté Qwant et alimentait aussi une fonction de lutte contre les abus. Le code établit cette capacité technique et son inclusion dans des versions de release ; il ne suffit pas à démontrer son déploiement sur tout le trafic, ses durées de conservation, la constitution effective d'un profil publicitaire longitudinal ou une transmission du DataHub à Microsoft.

Cette conclusion complète le chapitre 44 : le tracking n'est pas seulement un flux adressé à Bing. Le code montre aussi une journalisation détaillée opérée sur l'infrastructure de Qwant.

16. Source principale et références

Principaux fichiers contrôlés dans v1.32.1 :

  • www/application/models/logger.php ;
  • www/application/hooks/QwantHook.php ;
  • www/application/config/production/logger.php ;
  • www/application/libraries/search_service.php ;
  • www/application/controllers/LoggerClickAPIController.php ;
  • www/application/models/search/search_ads.php ;
  • www/application/models/httpgateway.php ;
  • www/application/models/user_model.php ;
  • www/application/core/MY_Controller.php.

← Retour au sommaire du dossier

⬇ Download